import { syncCodeLogger } from './logger/syncCodeLogger';
import { componentCompileLogger } from './logger/componentCompileLogger';
import * as vscode from 'vscode';
import { spawn } from 'child_process';
import { getRepoPath } from './utils/commonUtils';

// 标记是否正在执行同步代码命令
let isSyncingCode = false;

export function syncCode(args: any[]) {
    // 如果当前正在执行命令，则不允许再次触发
    if (isSyncingCode) {
        vscode.window.showInformationMessage('Sync Code is already running, please wait...');
        return;
    }

    if (args.length === 0) {
        vscode.window.showErrorMessage('No args provided, please see the log for more information');
        componentCompileLogger.show();
        componentCompileLogger.errorWithStack('No args provided');
        return;
    }

    const uri = args[0] as vscode.Uri;
    if (!uri || typeof uri.fsPath !== 'string') {
        vscode.window.showErrorMessage('Invalid URI provided, , please see the log for more information');
        componentCompileLogger.show();
        componentCompileLogger.errorWithStack('Invalid URI provided');
        return;
    }

    let path = uri.fsPath;
    // Check if path is a file, if not, append bundle.json to it
    const fs = require('fs');
    if (fs.existsSync(path) && fs.statSync(path).isDirectory()) {
        path = `${path}/bundle.json`;
        if (!fs.existsSync(path)) {
            vscode.window.showErrorMessage('Could not find bundle.json in the directory, please see the log for more information');
            componentCompileLogger.errorWithStack('Could not find bundle.json in the directory');
            return;
        }
    }
    
    componentCompileLogger.info(`bundle.json's path is : ${path}`);

    const pathParts = path.split(/[/\\]/);
    const parentFolderName = pathParts.length >= 2 ? pathParts.slice(-2, -1)[0] : '';

    if (!parentFolderName) {
        vscode.window.showErrorMessage('Could not extract parent folder name from path, please see the log for more information');
        componentCompileLogger.errorWithStack('Could not extract parent folder name from path');
        return;
    }
    componentCompileLogger.info(`parentFolderName is : ${parentFolderName}`);
    
    isSyncingCode = true;
    vscode.window.withProgress({
        location: vscode.ProgressLocation.Notification,
        title: `[${parentFolderName}]: Begin to Sync Code...`,
        cancellable: true
    },
    async (progress, token) => {
        // Execute ls command
        const dirPath = path.substring(0, path.lastIndexOf('/'));
        
        try {
            // 执行命令
            const result = await executeAndLogCommand(dirPath, parentFolderName, token);

            if (result && result.status === 'success') {
                // 成功时的操作
                vscode.window.showInformationMessage(`[build],[${parentFolderName}]: Sync Code Success`);
                return true;
            } else {
                vscode.window.showErrorMessage(`[${parentFolderName}]: Sync Code failed, ${result?.message}`);
                return false;
            }
        } catch (error) {
            // 发生错误时显示错误消息
            if (error instanceof Error) {
                componentCompileLogger.errorWithStack(error.message);
            } else {
                componentCompileLogger.errorWithStack("Sync Code failed");
            }
            vscode.window.showErrorMessage(`[${parentFolderName}]: Sync Code failed, Please check the log for more information`);     
            return false; // 表示操作失败
        } finally {
            isSyncingCode = false;
        }
    });
}

/**
 * 执行repo list命令，获取组件名称
 * @param dirPath bundle.json所在目录的全路径
 * @param parentFolderName bundle.json所在目录的父文件夹名称
 * @returns 组件名称
 */
async function getComponentName(dirPath: string, parentFolderName: string): Promise<{ componentName: string, repoRootPath: string }> {
    const repoRootPath = getRepoPath(dirPath);
    if (!repoRootPath) {
        componentCompileLogger.show();
        componentCompileLogger.error('Could not find .repo directory in any parent folder');
        vscode.window.showErrorMessage(`[${parentFolderName}]: Could not find .repo directory`);
        return { componentName: '', repoRootPath: '' };
    }

    // First run repo list to get the component name
    let componentName = parentFolderName;
    const { spawn } = require('child_process');
    const repoListProcess = spawn('repo', ['list'], { cwd: repoRootPath });
    
    let repoListOutput = '';
    
    repoListProcess.stdout.on('data', (data: Buffer) => {
        repoListOutput += data.toString();
    });
    
    // 等待repo list命令执行完成
    return await new Promise<void>((resolve, reject) => {
        repoListProcess.on('close', (code: number) => {
            if (code === 0) {
                resolve();
            } else {
                reject(new Error(`repo list command failed with code ${code}`));
            }
        });
        
        repoListProcess.on('error', (err: Error) => {
            reject(err);
        });
    }).then(() => {
        // Process the repo list output to find the component name
        const lines = repoListOutput.split('\n');
        const relativePath = dirPath.replace(repoRootPath + '/', '');
        
        componentCompileLogger.info(`Looking for component at relative path: ${relativePath}`);
        
        for (const line of lines) {
            // Fix for the correct format: "directory : component_name"
            const parts = line.trim().split(/\s*:\s*/);
            if (parts.length === 2) {
                const path = parts[0].trim();
                const name = parts[1].trim();
                if (path && relativePath.startsWith(path)) {
                    componentName = name;
                    componentCompileLogger.info(`Found component name: ${componentName} for path: ${path}`);
                    break;
                }
            }
        }

        return { componentName: componentName, repoRootPath: repoRootPath };
    }).catch((error: Error) => {
        componentCompileLogger.show();
        componentCompileLogger.errorWithStack(`Failed to get component name from repo list: ${error instanceof Error ? error.message : 'unknown error'}`);
        return { componentName: '', repoRootPath: '' };
    });
}

/**
 * 执行命令并记录日志
 * @param dirPath bundle.json所在目录的全路径
 * @param parentFolderName bundle.json所在目录的父文件夹名称
 * @param token 取消令牌
 * @returns 
 */
async function executeAndLogCommand(dirPath: string, parentFolderName: string, token?: vscode.CancellationToken) {
    componentCompileLogger.info(`Begin to repo sync, dirPath is ${dirPath}, parentFolderName is ${parentFolderName}`);
    
    const { componentName, repoRootPath } = await getComponentName(dirPath, parentFolderName);
    if (!componentName) {
        return { status: 'failed', message: 'Could not get component name' };
    }

    componentCompileLogger.info(`Component name is ${componentName}, repoRootPath is ${repoRootPath}`);
    
    return await executeRepoSync(repoRootPath, componentName, token);
}

/**
 * 执行repo sync命令
 * @param repoRootPath .repo目录所在目录
 * @param componentName 组件名称
 * @param token 取消令牌
 * @returns 
 */
function executeRepoSync(repoRootPath: string, componentName: string, token?: vscode.CancellationToken) {
    let commandStr = `repo sync -c build ${componentName}`;
    if (componentName === 'build') {
        commandStr = `repo sync -c build`;
    }
        
    // 将命令字符串分解为命令和参数
    const parts = commandStr.split(' ');
    const command = parts[0];
    const args = parts.slice(1);
    
    componentCompileLogger.info(`Executing command: ${commandStr} in directory: ${repoRootPath}`);
    
    const process = spawn(command, args, { 
        cwd: repoRootPath
    });

    // 实时处理标准输出
    process.stdout.on('data', (data) => {
        const output = data.toString().trim();
        if (output) {
            output.split('\n').forEach((line: string) => {
                if (line.trim()) {
                    syncCodeLogger.info(`  ${line}`);
                }
            });
        }
    });
        
    // 实时处理标准错误
    process.stderr.on('data', (data) => {
        const output = data.toString().trim();
        if (output) {
            output.split('\n').forEach((line: string) => {
                if (line.trim()) {
                    syncCodeLogger.info(`  ${line}`);
                }
            });
        }
    });
    
    return new Promise<{ status: string; message?: string }>((resolve, reject) => {
        // 保存对取消状态的引用
        let isCancelled = false;
        
        if (token) {
            token.onCancellationRequested(() => {
                isCancelled = true;
                process.kill();
                componentCompileLogger.info(`Sync Code cancelled by user`);
                reject({ status: 'failed', message: 'Sync Code cancelled by user' });
            });
        }
        
        process.on('close', (code) => {
            // 如果已经因为取消而解析了，就不要重复解析
            if (isCancelled) {
                return;
            }
            
            if (code === 0) {
                resolve({ status: 'success', message: 'Sync Code success' });
            } else {
                const errorMsg = `命令 ${commandStr} 执行失败，退出码: ${code}`;
                componentCompileLogger.errorWithStack(errorMsg);
                reject({ status: 'failed', message: "please check the log for more information" });
            }
        });
        
        process.on('error', (err) => {
            // 如果已经因为取消而解析了，就不要重复解析
            if (isCancelled) {
                return;
            }
            
            componentCompileLogger.errorWithStack(`command execution error: ${err.message}`);
            reject({ status: 'failed', message: "please check the log for more information" });
        });
    }).catch((error: Error) => {
        componentCompileLogger.errorWithStack(`command execution error: ${error.message}`);
        return { status: 'failed', message: "please check the log for more information" };
    });
}